﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MvcPatch
{
    public abstract class ImmutableDictionaryCache<TKey, TValue>
    {
        protected ImmutableDictionaryCache()
            : this(null)
        { }

        protected ImmutableDictionaryCache(IEqualityComparer<TKey> comparer)
        {
            this.m_storage = new Dictionary<TKey, TValue>(comparer);
        }

        protected abstract TValue Create(TKey key);

        private Dictionary<TKey, TValue> m_storage;
        private readonly object m_writeLock = new object();

        public TValue Get(TKey key)
        {
            TValue value;

            if (this.m_storage.TryGetValue(key, out value))
            {
                return value;
            }

            lock (this.m_writeLock)
            {
                if (this.m_storage.TryGetValue(key, out value))
                {
                    return value;
                }

                value = this.Create(key);
                var newStorage = this.m_storage.ToDictionary(
                    p => p.Key,
                    p => p.Value,
                    this.m_storage.Comparer);

                newStorage.Add(key, value);
                this.m_storage = newStorage;
            }

            return value;
        }
    }
}
